在Firefox 3.5中,我在Firebug控制台中输入:
false=={} // => evals to false {}==false // syntax error
对此有何解释?
{
在语句开头发出'语句块'(参见ECMA-262-3第12.1节),其中包含一个语句列表.
}
立即结束语句块,其中没有语句.没关系.但现在解析器正在寻找下一个语句:
==false
咦?那不是陈述; 语法错误.
什么是语句块?好吧,每次你说的时候,你都在写一个声明块:
if (something) { ... }
JavaScript将这些流控制语句定义为:
if "("")" [else ]
即.在单一的声明形式,没有大括号.然后,它允许您在任何可以使用单个语句的地方使用语句块,这意味着您可以使用if-braces-many-statements.但这也意味着你可以自己拥有一个语句块而没有相关的流控制语句.
这绝对没有实际意义!您可能会想到它会让您隐藏信息,但不会:
var a= 1; { var a= 2; } alert(a);
...导致2
,因为语句块本身不会创建新范围.
JavaScript以这种方式定义流控制和语句块,因为C(和从它派生的其他语言)做到了.{}
尽管如此,这些语言并没有将服务作为一个对象文字表达式,因此它们没有使这另一个JS错误的模糊性.
即使是这个想要的文字:
{ a: 1 }
是一个有效的语句块,因为':'用于表示语句中的标签.(并且1
是一个无用的表达式语句,省略了分号.)标签是从C继承的另一个很少在JavaScript中使用的功能.它们并不像块一样毫无意义,但它们很少需要并且通常被认为是味道不佳.
(具有两个属性的文字将导致语法错误,因为对象文字使用逗号分隔符,但标记的语句必须用分号分隔.)
这不是 JavaScript松散语法可以通过对您认为是表达式的某些其他声明进行绊倒的唯一地方.
好的,我已经研究了ECMAScript规范(PDF),并且我有一个讨论,讨论了BNF语法.
从主符号开始解析ECMAScript源,称为Program
:
Program: SourceElements
SourceElements'(递归)定义是这样的:
SourceElements : SourceElement SourceElements SourceElement
SourceElement定义为:
SourceElement : Statement FunctionDeclaration
我们感兴趣的是对象文字语法,所以我们忽略FunctionDeclaration并查看Statement符号:
Statement : Block VariableStatement EmptyStatement ExpressionStatement IfStatement IterationStatement ContinueStatement BreakStatement ReturnStatement WithStatement LabelledStatement SwitchStatement ThrowStatement TryStatement
我不确定列表顺序是否重要(这是它们在规范中的含义),但是...对象文字是一个ExpressionStatement,标准说明如下(第12.4节):
请注意,ExpressionStatement不能以开括号大括号开头,因为这可能使其与Block不一致.此外,ExpressionStatement不能以function关键字开头,因为这可能使其与FunctionDeclaration不一致.
所以我们可能在程序的开头有一个表达式,但它不能以一个开头大括号({
)开头.这就是为什么以下工作正常:
({} == false);
alert({} == false);
!{} == false;